package com.xw.service.impl;

import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xw.constant.TokenConstant;
import com.xw.dto.MenuDTO;
import com.xw.entity.Admin;
import com.xw.entity.Menu;
import com.xw.entity.Role;
import com.xw.enums.ResultEnum;
import com.xw.mapper.AdminMapper;
import com.xw.mapper.MenuMapper;
import com.xw.mapper.RoleMapper;
import com.xw.service.IAdminService;
import com.xw.utils.ResultVOUtil;
import com.xw.utils.TimedCacheUtil;
import com.xw.vo.ResultVO;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author y
 * @since 2021-09-14
 */
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {
    @Resource
    private AdminMapper adminMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private MenuMapper menuMapper;


    @Override
    public ResultVO<?> toLogin(String userName, String pwd) {
        if (ObjectUtils.isEmpty(userName) || ObjectUtils.isEmpty(pwd)) {
            return ResultVOUtil.fail(ResultEnum.PARAM_ERROR);
        }
        Map<String, Object> map = MapUtil.newHashMap();


        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userName", userName);
        queryWrapper.eq("pwd", SecureUtil.md5(pwd + pwd).toUpperCase());
        Admin result = adminMapper.selectOne(queryWrapper);
        if (result != null) {
            String randomToken = RandomUtil.randomStringUpper(32);
            //判断是否已经登录
            String tokenName = String.format(TokenConstant.TOKEN_PREFIX, result.getId().toString());
            TimedCache<String, String> tokenTimedCache = TimedCacheUtil.TOKEN_TIMED_CACHE;
            if (tokenTimedCache.containsKey(tokenName)) {
                map.put("token", tokenTimedCache.get(tokenName));
            } else {
                tokenTimedCache.put(tokenName, randomToken);
                map.put("token", randomToken);
            }
            //查看菜单
            Integer roleId = result.getRoleId();
            Role role = roleMapper.selectById(roleId);
            if (role == null) {
                return ResultVOUtil.fail(ResultEnum.ROLE_NOT_EXIST);
            }
            List<MenuDTO> menuDTOList = getMenu(role);

            map.put("userInfo", result);
            map.put("menuDTOList", menuDTOList);
            return ResultVOUtil.success(map);
        }
        return ResultVOUtil.fail(ResultEnum.WRONG_ACCOUNT_OR_PASSWORD);
    }

    @Override
    public ResultVO<?> logout(String userId) {
        TimedCache<String, String> tokenTimedCache = TimedCacheUtil.TOKEN_TIMED_CACHE;
        String format = tokenTimedCache.get(String.format(TokenConstant.TOKEN_PREFIX, userId));
        tokenTimedCache.remove(String.format(TokenConstant.TOKEN_PREFIX, userId));
        return ResultVOUtil.success();
    }

    @Override
    public ResultVO<?> updPwd(String userId, String oldPwd, String newPwd) {
        LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Admin::getId, userId);
        queryWrapper.eq(Admin::getPwd, SecureUtil.md5(oldPwd + oldPwd).toUpperCase());
        Admin result = adminMapper.selectOne(queryWrapper);
        if (!ObjectUtils.isEmpty(result)) {
            result.setPwd(SecureUtil.md5(newPwd + newPwd).toUpperCase());
            int update = adminMapper.updateById(result);
            return update > 0 ? ResultVOUtil.success() : ResultVOUtil.fail(ResultEnum.PLEASE_TRY_AGAIN_LATER);
        }
        return ResultVOUtil.fail(ResultEnum.OLD_PWD_ERR);
    }

    private List<MenuDTO> getMenu(Role role) {

        String[] split = role.getMenuPower().split(",");
        //得到菜单所有id
        List<String> list = recursiveIds(new ArrayList<String>(), split);

        List<Menu> menuList = menuMapper.selectBatchIds(list);
        //拿到所拥有菜单的root节点
        List<Menu> collect = menuList.stream().sorted(Comparator.comparing(Menu::getSequence).reversed()).filter(m -> m.getParentId() == 0).collect(Collectors.toList());
        List<MenuDTO> menuDTOList = new ArrayList<>();
        for (Menu menu : collect) {
            MenuDTO menuDTO = new MenuDTO();
            menuDTO.setId(menu.getId());
            menuDTO.setTitle(menu.getTitle());
            menuDTO.setUrl(menu.getUrl());
            menuDTO.setIcon(menu.getIcon());
            menuDTO.setChildren(recursiveChildren(new ArrayList<MenuDTO>(), menu.getId(), list));

            menuDTOList.add(menuDTO);

        }

        return menuDTOList;

    }

    private List<MenuDTO> recursiveChildren(ArrayList<MenuDTO> menuDTOArrayList, Integer id, List<String> ownIds) {

        List<Menu> selectList = menuMapper.selectList(new QueryWrapper<Menu>().eq("parent_id", id).orderByDesc("sequence"));

        selectList.stream().filter(e -> ownIds.contains(String.valueOf(e.getId()))).forEach(e -> {
            MenuDTO menuDTO = new MenuDTO();
            menuDTO.setId(e.getId());
            menuDTO.setTitle(e.getTitle());
            menuDTO.setUrl(e.getUrl());
            menuDTO.setIcon(e.getIcon());
            menuDTO.setChildren(recursiveChildren(new ArrayList<>(), e.getId(), ownIds));
            menuDTOArrayList.add(menuDTO);
        });
        return menuDTOArrayList;

    }

    //
    private List<String> recursiveIds(ArrayList<String> strings, String[] split) {

        for (String s : split) {
            if (!strings.contains(s)) {
                strings.add(s);
            }

            Menu menu1 = menuMapper.selectById(s);

            if (menu1 != null) {
                Menu menu2 = menuMapper.selectById(menu1.getParentId());
                if (menu2 != null) {
                    if (!strings.contains(menu2.getId().toString())) {
                        strings.add(menu2.getId().toString());
                    }
                    if (menu2.getParentId() != 0) {
                        recursiveIds(strings, new String[]{menu2.getId().toString()});
                    }
                }

            }

        }
        return strings;

    }
}